//
//  BigNum.h
//  BigNum
//
//  Created by Sam Jaffe on 9/18/12.
//  Copyright (c) 2012 Sam Jaffe. All rights reserved.
//

#pragma once

#include <vector>
#include <iostream>
#include <cmath>
#include <string>

typedef uint32_t ul;
typedef int64_t ll;
typedef uint64_t ull;
typedef std::vector<ul> BigNumBlock;
typedef BigNumBlock::iterator BigNumIter;

ull DSIZE_MAX = (0 >> sizeof(ull)) ^ (0 >> sizeof(ul));

class BigUInt;
class BigInt;

class BigNumber {
private:
    static std::string make_string(BigNumber num);
protected:
    BigNumBlock blocks;
    BigNumber();
    
public:
    virtual ~BigNumber();
    BigNumber& operator= (const BigNumber& b);
    
    BigNumber& add(const BigNumber& b);
    BigNumber& sub(const BigNumber& b);
    BigNumber& mult(const BigNumber& b);
    BigNumber& div(const BigNumber& b);
    BigNumber& mod(const BigNumber& b);
    
    BigNumber& bflip();
    BigNumber& band(const BigNumber& b);
    BigNumber& bor(const BigNumber& b);
    BigNumber& bxor(const BigNumber& b);
    BigNumber& bin(const BigNumber& b);
    BigNumber& bout(const BigNumber& b);
    BigNumber& bleft(const BigNumber& b) {return bin(b);}
    BigNumber& bright(const BigNumber& b) {return bout(b);}
    
    void sum(const BigNumber& a, const BigNumber& b);
    void diff(const BigNumber& a, const BigNumber& b);
    void product(const BigNumber& a, const BigNumber& b);
    void quotient(const BigNumber& a, const BigNumber& b);
    void modulo(const BigNumber& a, const BigNumber& b);
    
    void bflip(const BigNumber& a);
    void band(const BigNumber& a, const BigNumber& b);
    void bor(const BigNumber& a, const BigNumber& b);
    void bxor(const BigNumber& a, const BigNumber& b);
    void bin(const BigNumber& a, const BigNumber& b);
    void bout(const BigNumber& a, const BigNumber& b);
    void bleft(const BigNumber& a, const BigNumber& b) {return bin(a, b);}
    void bright(const BigNumber& a, const BigNumber& b) {return bout(a, b);}

    BigNumber operator+ (const BigNumber& b) const;
    BigNumber operator- (const BigNumber& b) const;
    BigNumber operator* (const BigNumber& b) const;
    BigNumber operator/ (const BigNumber& b) const;
    BigNumber operator% (const BigNumber& b) const;

    virtual BigNumber operator- () const;

    virtual bool operator== (const BigNumber& b) const;
    virtual bool operator!= (const BigNumber& b) const;
    virtual bool operator>= (const BigNumber& b) const;
    virtual bool operator> (const BigNumber& b) const;
    virtual bool operator<= (const BigNumber& b) const;
    virtual bool operator< (const BigNumber& b) const;

    BigNumber operator~ () const;
    BigNumber operator& (const BigNumber& b) const;
    BigNumber operator| (const BigNumber& b) const;
    BigNumber operator^ (const BigNumber& b) const;
    BigNumber operator<< (const BigNumber& b) const;
    BigNumber operator>> (const BigNumber& b) const;
    
    BigNumBlock getBlocks();

    virtual operator std::string() const;
    virtual operator int() const;
    virtual operator unsigned int() const;
    virtual operator long int() const;
    virtual operator unsigned long int() const;
    virtual operator long long int() const;
    virtual operator unsigned long long int() const;
};

std::ostream& operator<< (std::ostream& a, BigNumber& b);
